/* **********************************************************
 * Copyright (c) 2002-2008 VMware, Inc.  All rights reserved.
 * **********************************************************/

/*
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * * Neither the name of VMware, Inc. nor the names of its contributors may be
 *   used to endorse or promote products derived from this software without
 *   specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */

/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2002-2003 Massachusetts Institute of Technology */

#ifdef LOAD_TO_CONST
#ifndef __LOADTOCONST_H_
#define __LOADTOCONST_H_

#define NUM_VALUES_FOR_SPECULATION 40
#define SAMPLE_PERCENT (9/10)


#define MAX_TRACES_WAITING_FOR_LTC 20
#include "instr.h"

struct ltc_mem_ref_data{
    opnd_t opnd;
    int vals[NUM_VALUES_FOR_SPECULATION];
    int addresses[NUM_VALUES_FOR_SPECULATION];
};
struct ltc_data{
    struct ltc_mem_ref_data *mem_refs;
    int num_mem_addresses;
    int num_mem_samples;
    bool ltc_already_optimized;
};

#ifdef LTC_STATS
extern int safe_taken,opt_taken,addrs_analyzed,addrs_made_const,traces_analyzed,addrs_seen;
#endif

void analyze_memrefs(dcontext_t *dcontext, app_pc tag, instrlist_t *trace);


int check_mem_refs(app_pc tag, int errno, reg_t eflags,
                   reg_t reg_edi, reg_t reg_esi, reg_t reg_ebp, reg_t reg_esp,
                   reg_t reg_ebx, reg_t reg_edx, reg_t reg_ecx, reg_t reg_eax);
int get_mem_address(dcontext_t *dcontext,opnd_t mem_access,int regs[8]);
int get_mem_val(dcontext_t *dcontext,opnd_t mem_access,int address);
void ltc_trace(dcontext_t *dcontext, fragment_t *, instrlist_t *trace);
void remove_mem_ref_check(dcontext_t *dcontext,instrlist_t *trace);

#ifdef SIDELINE
void LTC_examine_traces(void);
void LTC_fragment_delete(fragment_t *frag);
#endif

void LTC_online_optimize_and_replace(dcontext_t *dcontext, app_pc tag,fragment_t *curfrag);
void do_single_LTC(dcontext_t *dcontext,instrlist_t *trace, opnd_t mem_access, opnd_t value);
bool should_replace_load(dcontext_t *dcontext,struct ltc_mem_ref_data data);
opnd_t value_to_replace(struct ltc_mem_ref_data);
bool instr_replace_reg_with_const_in_src(dcontext_t *dcontext,instr_t *in,int reg,int val);
bool instr_replace_reg_with_const_in_dst(dcontext_t *dcontext,instr_t *in,int reg,int val);
instrlist_t *save_eflags_list(dcontext_t *dcontext,fragment_t *frag);
instrlist_t *restore_eflags_list(dcontext_t *dcontext,fragment_t *frag);
void change_cbr_due_to_reversed_cmp(instr_t *in);
bool pc_reads_flags_before_writes(dcontext_t *dcontext,app_pc target);

instr_t *fix_cmp_containing_constant(dcontext_t *dcontext,instrlist_t *trace,instr_t *in,
                                   opnd_t orig_op1,opnd_t orig_op2);

void replace_self_loop_with_opnd(dcontext_t *dcontext, app_pc tag,
                                 instrlist_t *ilist, opnd_t desiredtarget);
#define TRANSPOSE true
#define NO_TRANSPOSE false
bool safe_to_transpose_cmp(dcontext_t *dcontext,instr_t *testinstr);
bool safe_to_delete_cmp(dcontext_t *dcontext,instr_t *testinstr);
bool safe_to_modify_cmp(dcontext_t *dcontext,instr_t *testinstr, bool transpose);
bool becomes_ubr_from_cmp(instr_t *in,int op1, int op2);
bool opnd_replace_reg_with_val(opnd_t *opnd, int old_reg, int val);
void constant_propagate(dcontext_t *dcontext, instrlist_t *trace,app_pc tag);
void pop_instr_off_list(dcontext_t *dcontext,instrlist_t *trace,int opcode);
void instr_optimize_constant(dcontext_t *dcontext, instr_t *in);
bool instr_flag_write_necessary(dcontext_t *dcontext, instr_t *in);

void instr_replace_inplace(dcontext_t *dcontext, instr_t *in, instr_t *);
void instr_arithmatic_simplify(dcontext_t *dcontext, instr_t *in);
void instrlist_remove_nops(dcontext_t *dcontext,instrlist_t *trace);
bool instrlist_depends_on_reg(dcontext_t *dcontext, instrlist_t *trace, int reg);
void instr_add_to_exitexec_list(dcontext_t *,instr_t *in,instr_t *exitinstr);
void instrlist_setup_pseudo_exitstubs(dcontext_t *dcontext,instrlist_t *trace);
#endif
#endif

